"""
FIPA-ACL (Foundation for Intelligent Physical Agents - Agent Communication Language) 实现
支持智能体间基于标准协议的直接通信和协商
"""
from typing import Dict, Any, Optional, List
from enum import Enum
from dataclasses import dataclass
from datetime import datetime
import json
import uuid
from utils.logger import Logger

logger = Logger.get_logger("fipa_acl")


class Performative(Enum):
    """FIPA-ACL 标准执行原语"""
    REQUEST = "request"  # 请求执行动作
    INFORM = "inform"    # 通知信息
    QUERY_IF = "query-if"  # 条件查询
    CFP = "cfp"         # Call For Proposal
    PROPOSE = "propose"   # 提议
    ACCEPT_PROPOSAL = "accept-proposal"  # 接受提议
    REJECT_PROPOSAL = "reject-proposal"  # 拒绝提议
    FAILURE = "failure"   # 执行失败
    NOT_UNDERSTOOD = "not-understood"   # 无法理解
    CONFIRM = "confirm"   # 确认
    DISCONFIRM = "disconfirm"  # 否认


@dataclass
class AgentIdentifier:
    """智能体标识符"""
    name: str
    address: str
    agent_type: str
    capabilities: List[str]
    
    def to_dict(self) -> Dict[str, Any]:
        return {
            "name": self.name,
            "address": self.address,
            "agent_type": self.agent_type,
            "capabilities": self.capabilities
        }


@dataclass
class ACLMessage:
    """ACL消息结构"""
    message_id: str
    performative: Performative
    sender: AgentIdentifier
    receivers: List[AgentIdentifier]
    reply_to: Optional[AgentIdentifier] = None
    content: Optional[Any] = None
    language: str = "JSON"
    encoding: str = "UTF-8"
    ontology: str = "MAESS-Ontology"
    protocol: str = "fipa-request"
    conversation_id: str = ""
    reply_with: Optional[str] = None
    in_reply_to: Optional[str] = None
    timestamp: datetime = None
    
    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = datetime.utcnow()
        if not self.conversation_id:
            self.conversation_id = str(uuid.uuid4())
    
    def to_dict(self) -> Dict[str, Any]:
        return {
            "message_id": self.message_id,
            "performative": self.performative.value,
            "sender": self.sender.to_dict(),
            "receivers": [r.to_dict() for r in self.receivers],
            "reply_to": self.reply_to.to_dict() if self.reply_to else None,
            "content": self.content,
            "language": self.language,
            "encoding": self.encoding,
            "ontology": self.ontology,
            "protocol": self.protocol,
            "conversation_id": self.conversation_id,
            "reply_with": self.reply_with,
            "in_reply_to": self.in_reply_to,
            "timestamp": self.timestamp.isoformat()
        }


class FIPAACLProtocol:
    """FIPA-ACL协议实现"""
    
    def __init__(self, agent_id: str, redis_client):
        self.agent_id = agent_id
        self.redis_client = redis_client
        self.message_handlers = {}
        self.conversations = {}  # conversation_id -> conversation_state
        self._register_default_handlers()
    
    def _register_default_handlers(self):
        """注册默认消息处理器"""
        self.message_handlers[Performative.REQUEST] = self._handle_request
        self.message_handlers[Performative.INFORM] = self._handle_inform
        self.message_handlers[Performative.CFP] = self._handle_cfp
        self.message_handlers[Performative.PROPOSE] = self._handle_propose
        self.message_handlers[Performative.ACCEPT_PROPOSAL] = self._handle_accept_proposal
        self.message_handlers[Performative.REJECT_PROPOSAL] = self._handle_reject_proposal
        self.message_handlers[Performative.FAILURE] = self._handle_failure
        self.message_handlers[Performative.NOT_UNDERSTOOD] = self._handle_not_understood
    
    async def send_message(self, message: ACLMessage) -> bool:
        """发送ACL消息"""
        try:
            # 将消息序列化并存储到Redis，供目标智能体消费
            message_key = f"acl_message:{message.message_id}"
            message_data = json.dumps(message.to_dict())
            
            # 存储消息内容
            self.redis_client.setex(message_key, 3600, message_data)  # 1小时过期
            
            # 为每个接收者创建待处理消息索引
            for receiver in message.receivers:
                receiver_key = f"acl_inbox:{receiver.name}"
                self.redis_client.lpush(receiver_key, message_key)
                self.redis_client.expire(receiver_key, 3600)
            
            logger.info(f"ACL消息发送成功: {message.message_id} -> {[r.name for r in message.receivers]}")
            return True
            
        except Exception as e:
            logger.error(f"ACL消息发送失败: {message.message_id}, error={str(e)}")
            return False
    
    async def receive_messages(self, agent_name: str, timeout: float = 5.0) -> List[ACLMessage]:
        """接收ACL消息"""
        messages = []
        inbox_key = f"acl_inbox:{agent_name}"
        
        try:
            # 获取消息键列表
            message_keys = self.redis_client.lrange(inbox_key, 0, -1)
            
            for message_key in message_keys:
                message_key = message_key.decode('utf-8') if isinstance(message_key, bytes) else message_key
                
                # 获取消息内容
                message_data = self.redis_client.get(message_key)
                if message_data:
                    message_dict = json.loads(message_data.decode('utf-8'))
                    message = self._dict_to_acl_message(message_dict)
                    messages.append(message)
                    
                    # 从收件箱中移除已处理的消息
                    self.redis_client.lrem(inbox_key, 0, message_key)
                    
            logger.info(f"ACL消息接收成功: {agent_name} 收到 {len(messages)} 条消息")
            return messages
            
        except Exception as e:
            logger.error(f"ACL消息接收失败: {agent_name}, error={str(e)}")
            return []
    
    async def process_message(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理接收到的消息"""
        handler = self.message_handlers.get(message.performative)
        if handler:
            try:
                return await handler(message)
            except Exception as e:
                logger.error(f"ACL消息处理失败: {message.performative}, error={str(e)}")
                return self._create_error_reply(message, str(e))
        else:
            return self._create_not_understood_reply(message)
    
    def _dict_to_acl_message(self, message_dict: Dict[str, Any]) -> ACLMessage:
        """将字典转换为ACL消息"""
        sender = AgentIdentifier(**message_dict['sender'])
        receivers = [AgentIdentifier(**r) for r in message_dict['receivers']]
        reply_to = AgentIdentifier(**message_dict['reply_to']) if message_dict.get('reply_to') else None
        
        return ACLMessage(
            message_id=message_dict['message_id'],
            performative=Performative(message_dict['performative']),
            sender=sender,
            receivers=receivers,
            reply_to=reply_to,
            content=message_dict.get('content'),
            language=message_dict.get('language', 'JSON'),
            encoding=message_dict.get('encoding', 'UTF-8'),
            ontology=message_dict.get('ontology', 'MAESS-Ontology'),
            protocol=message_dict.get('protocol', 'fipa-request'),
            conversation_id=message_dict.get('conversation_id', ''),
            reply_with=message_dict.get('reply_with'),
            in_reply_to=message_dict.get('in_reply_to'),
            timestamp=datetime.fromisoformat(message_dict['timestamp'])
        )
    
    async def _handle_request(self, message: ACLMessage) -> ACLMessage:
        """处理请求消息"""
        logger.info(f"处理REQUEST消息: {message.message_id}")
        # 这里应该调用具体的业务逻辑
        content = message.content or {}
        action = content.get('action')
        
        if action == 'process_task':
            # 处理任务请求
            result = await self._process_task_request(content.get('task_data'))
            return self._create_reply(message, Performative.INFORM, result)
        else:
            return self._create_not_understood_reply(message)
    
    async def _handle_inform(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理通知消息"""
        logger.info(f"处理INFORM消息: {message.message_id}")
        # 更新对话状态
        if message.conversation_id in self.conversations:
            self.conversations[message.conversation_id]['last_update'] = datetime.utcnow()
        return None
    
    async def _handle_cfp(self, message: ACLMessage) -> ACLMessage:
        """处理招标请求"""
        logger.info(f"处理CFP消息: {message.message_id}")
        content = message.content or {}
        task_requirements = content.get('requirements', {})
        
        # 评估是否能满足要求
        capability_match = self._evaluate_capability_match(task_requirements)
        
        if capability_match >= 0.8:  # 80%匹配度
            proposal = {
                'agent_id': self.agent_id,
                'capability_score': capability_match,
                'estimated_time': 30,  # 预计完成时间（秒）
                'cost': 1.0  # 成本评分
            }
            return self._create_reply(message, Performative.PROPOSE, proposal)
        else:
            return self._create_reply(message, Performative.REJECT_PROPOSAL, 
                                    {'reason': 'capability_mismatch'})
    
    async def _handle_propose(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理提议消息"""
        logger.info(f"处理PROPOSE消息: {message.message_id}")
        # 这里应该实现提议评估逻辑
        return None
    
    async def _handle_accept_proposal(self, message: ACLMessage) -> ACLMessage:
        """处理接受提议"""
        logger.info(f"处理ACCEPT_PROPOSAL消息: {message.message_id}")
        content = message.content or {}
        task_data = content.get('task_data', {})
        
        # 开始执行任务
        result = await self._execute_contract(task_data)
        return self._create_reply(message, Performative.INFORM, result)
    
    async def _handle_reject_proposal(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理拒绝提议"""
        logger.info(f"处理REJECT_PROPOSAL消息: {message.message_id}")
        return None
    
    async def _handle_failure(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理失败消息"""
        logger.error(f"收到FAILURE消息: {message.message_id}, content={message.content}")
        return None
    
    async def _handle_not_understood(self, message: ACLMessage) -> Optional[ACLMessage]:
        """处理无法理解消息"""
        logger.warning(f"收到NOT_UNDERSTOOD消息: {message.message_id}")
        return None
    
    def _create_reply(self, original_message: ACLMessage, performative: Performative, content: Any) -> ACLMessage:
        """创建回复消息"""
        return ACLMessage(
            message_id=str(uuid.uuid4()),
            performative=performative,
            sender=original_message.receivers[0],  # 假设第一个接收者是发送者
            receivers=[original_message.sender],
            content=content,
            conversation_id=original_message.conversation_id,
            in_reply_to=original_message.message_id
        )
    
    def _create_error_reply(self, original_message: ACLMessage, error_message: str) -> ACLMessage:
        """创建错误回复"""
        return self._create_reply(original_message, Performative.FAILURE, 
                                {'error': error_message})
    
    def _create_not_understood_reply(self, original_message: ACLMessage) -> ACLMessage:
        """创建无法理解回复"""
        return self._create_reply(original_message, Performative.NOT_UNDERSTOOD,
                                {'reason': 'unsupported_performative'})
    
    async def _process_task_request(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """处理任务请求"""
        # 这里应该调用具体的Agent处理逻辑
        return {
            'status': 'success',
            'result': f"任务处理完成: {task_data.get('task_id', 'unknown')}",
            'agent_id': self.agent_id
        }
    
    def _evaluate_capability_match(self, requirements: Dict[str, Any]) -> float:
        """评估能力匹配度"""
        # 这里应该实现具体的能力评估逻辑
        return 0.9  # 模拟90%匹配度
    
    async def _execute_contract(self, task_data: Dict[str, Any]) -> Dict[str, Any]:
        """执行合同任务"""
        # 这里应该实现具体的合同执行逻辑
        return {
            'status': 'success',
            'result': f"合同执行完成: {task_data.get('contract_id', 'unknown')}",
            'agent_id': self.agent_id
        }


# 使用示例
async def example_usage():
    """FIPA-ACL使用示例"""
    from middleware.redis_adapter import get_redis_adapter
    
    redis_client = get_redis_adapter()
    
    # 创建两个智能体的协议实例
    agent1_protocol = FIPAACLProtocol("text_qa_agent_001", redis_client)
    agent2_protocol = FIPAACLProtocol("multi_modal_agent_001", redis_client)
    
    # 创建智能体标识符
    agent1_id = AgentIdentifier(
        name="text_qa_agent_001",
        address="http://localhost:8001",
        agent_type="text_qa",
        capabilities=["text_processing", "question_answering"]
    )
    
    agent2_id = AgentIdentifier(
        name="multi_modal_agent_001", 
        address="http://localhost:8002",
        agent_type="multi_modal",
        capabilities=["image_processing", "vqa", "ocr"]
    )
    
    # 创建请求消息
    request_message = ACLMessage(
        message_id=str(uuid.uuid4()),
        performative=Performative.REQUEST,
        sender=agent1_id,
        receivers=[agent2_id],
        content={
            'action': 'process_task',
            'task_data': {
                'task_id': 'task_001',
                'type': 'image_question',
                'question': '这张图片里有什么？',
                'image_url': 'http://example.com/image.jpg'
            }
        }
    )
    
    # 发送消息
    await agent1_protocol.send_message(request_message)
    
    # 接收消息
    received_messages = await agent2_protocol.receive_messages("multi_modal_agent_001")
    
    # 处理消息
    for message in received_messages:
        reply = await agent2_protocol.process_message(message)
        if reply:
            await agent2_protocol.send_message(reply)


if __name__ == "__main__":
    import asyncio
    asyncio.run(example_usage())